#include "session.h"
#include "server.h"
#include "logic.h"
#include "singleton.hpp"

#include <boost/asio/detail/socket_ops.hpp>
#include <cstdint>
#include <cstring>
#include <mutex>
#include <thread>

void Session::start()
{
    memset(_data, 0, sizeof(_data));

    auto self = shared_from_this();

    _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), 
    [this, self](const boost::system::error_code& error, size_t bytes_transferred) {
            handle_read(error, bytes_transferred, self);
    });
}


void Session::handle_read(const boost::system::error_code& error, size_t bytes_transferred, std::shared_ptr<Session> self)
{
    if(error)
    {   
        std::cout << "read error\n";
        _server->delete_session(_uuid);
        return;
    }

    uint32_t copy_len = 0; //已结处理长度
    while(bytes_transferred > 0)
    {
        //收到的数据不足头部大小
        if(!_head_parse_done)
        {
            if(bytes_transferred + _recv_head_msg->_cur_len < HEAD_TOTAL_LEN)
            {
                memcpy(_recv_head_msg->_data + _recv_head_msg->_cur_len, _data + copy_len, bytes_transferred);
                _recv_head_msg->_cur_len += bytes_transferred;

                memset(_data, 0 , MAX_LENGTH);
                _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), 
                [this, self](const boost::system::error_code& error, size_t bytes_transferred) {
                        handle_read(error, bytes_transferred, self);
                });
                return;
            }

            //收到的数据足够头部大小
            uint16_t head_remain_len = HEAD_TOTAL_LEN - _recv_head_msg->_cur_len;  //头部剩余未解析的长度
            memcpy(_recv_head_msg->_data + _recv_head_msg->_cur_len, _data + copy_len, head_remain_len);

            copy_len += head_remain_len;
            bytes_transferred -= head_remain_len;

            //打印头部信息
            uint16_t msg_len = 0;
            uint16_t msg_id = 0;
            memcpy(&msg_id, _recv_head_msg->_data, HEAD_MSG_ID);
            memcpy(&msg_len, _recv_head_msg->_data + HEAD_MSG_ID, HEAD_MSG_LEN);
            msg_id = boost::asio::detail::socket_ops::network_to_host_short(msg_id);
            msg_len = boost::asio::detail::socket_ops::network_to_host_short(msg_len);
            std::cout << "msg_id: " << msg_id << std::endl;
            std::cout << "msg_len: " << msg_len << std::endl;
            if(msg_len > MAX_LENGTH)
            {
                std::cout << "msg length error\n";
                _server->delete_session(_uuid);
                return;
            }

            _recv__msg = std::make_shared<RecvNode>(msg_len, msg_id);

            //消息的长度小于头部规定的长度
            if(bytes_transferred < msg_len)
            {
                memcpy(_recv__msg->_data + _recv__msg->_cur_len, _data + copy_len, bytes_transferred);
                _recv__msg->_cur_len += bytes_transferred;
                
                memset(_data, 0 , MAX_LENGTH);
                _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), 
                [this, self](const boost::system::error_code& error, size_t bytes_transferred) {
                        handle_read(error, bytes_transferred, self);
                });
                _head_parse_done = true;
                return;
            }

            memcpy(_recv__msg->_data + _recv__msg->_cur_len, _data + copy_len, msg_len);
            _recv__msg->_cur_len += msg_len;
            copy_len += msg_len;
            bytes_transferred -= msg_len;
            _recv__msg->_data[_recv__msg->_total_len] = '\0';
            // std::cout << "msg_id: " << _recv__msg->_msg_id << std::endl;
            // std::cout << "msg: " << _recv__msg->_data << std::endl;

            Singleton<Logic>::GetInstance()->post_task(std::make_shared<Task>(self, _recv__msg));
            // send(_recv__msg->_data, _recv__msg->_total_len, _recv__msg->_msg_id);
            // _recv__msg->Clear();
            _head_parse_done = false;

            if(bytes_transferred <= 0)
            {
                memset(_data, 0 , MAX_LENGTH);
                _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), 
                [this, self](const boost::system::error_code& error, size_t bytes_transferred) {
                        handle_read(error, bytes_transferred, self);
                });

                return;
            }

            continue;
        }
        
        //已经处理完头部，处理上次未接受完的消息数据
        uint16_t remain_msg_len = _recv__msg->_total_len - _recv__msg->_cur_len;
        if(bytes_transferred < remain_msg_len)
        {
            memcpy(_recv__msg->_data + _recv__msg->_cur_len, _data + copy_len, bytes_transferred);
            _recv__msg->_cur_len += bytes_transferred;
            memset(_data, 0 , MAX_LENGTH);
            _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), 
            [this, self](const boost::system::error_code& error, size_t bytes_transferred) {
                    handle_read(error, bytes_transferred, self);
            });
            return;
        }

        memcpy(_recv__msg->_data + _recv__msg->_cur_len, _data + copy_len, remain_msg_len);
        _recv__msg->_cur_len += remain_msg_len;
        copy_len += remain_msg_len;
        bytes_transferred -= remain_msg_len;
        _recv__msg->_data[_recv__msg->_total_len] = '\0';
        // std::cout << "receive msg_id: " << _recv__msg->_msg_id << std::endl;
        // std::cout << "receive data is " << _recv__msg->_data << std::endl;

        Singleton<Logic>::GetInstance()->post_task(std::make_shared<Task>(self, _recv__msg));
        // send(_recv__msg->_data, _recv__msg->_total_len, _recv__msg->_msg_id);
        // _recv__msg->Clear();
        _head_parse_done = false;

        if(bytes_transferred <= 0)
        {
            memset(_data, 0 , MAX_LENGTH);
            _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), 
            [this, self](const boost::system::error_code& error, size_t bytes_transferred) {
                    handle_read(error, bytes_transferred, self);
            });

            return;
        }
        continue;
    }

}


void Session::handle_write(const boost::system::error_code& error, size_t bytes_transferred, std::shared_ptr<Session> self)
{
    if(error)
    {
        std::cout << "write error\n";
        _server->delete_session(_uuid);
        return;
    }

    std::unique_lock<std::mutex> lock(_send_queue_lock);
    
    _send_queue.pop();
    if(_send_queue.empty())
    {
        return;
    }

    auto& msg = _send_queue.front();

    memset(_data, 0, MAX_LENGTH);
    boost::asio::async_write(_socket, boost::asio::buffer(msg->_data, msg->_total_len), 
    [this, self](const boost::system::error_code& error, std::size_t bytes_transferred) {
        handle_write(error, bytes_transferred, self);
    });
}


void Session::send(const char* msg, uint16_t len, uint16_t msg_id)
{
    bool pending = false;
    std::unique_lock<std::mutex> lock(_send_queue_lock);
    if(!_send_queue.empty())
    {
        pending = true;
    }

    std::shared_ptr<SendNode> node = std::make_shared<SendNode>(msg, len, msg_id);
    _send_queue.push(node);
    
    if(pending)
    {
        return;
    }

    auto self = shared_from_this();
    boost::asio::async_write(_socket, boost::asio::buffer(node->_data, node->_total_len), 
    [this, self](const boost::system::error_code& error, std::size_t bytes_transferred) {
        handle_write(error, bytes_transferred, self);
    });
}